
剛開始學的時候,很常把這兩個英文名稱搞混XD
光看解釋,可能看不出兩者的差異,等等看範例會更清楚
廣義來說兩者都是在明確定義型別,但型別註釋主要用於型別的安全檢查和編譯時檢查,而型別斷言則是一種「逃逸機制」,可以在特定情況下覆蓋 TypeScript 的型別推斷
關於型別註釋,有興趣可以看這篇文章
🔗 Day12 - 型別註釋 & 型別推斷
本篇文章將一起來了解「Type Assertion 型別斷言」的語法和使用時機
型別斷言就很像在告訴編譯器說:「來~相信我,這邊就聽我的,我知道我自己在做什麼」
型別斷言是告訴編譯器,在編譯期間將某個值視為另一個型別。如果斷言錯誤,是有可能在運行時造成錯誤的
使用時機:當你有十足把握確定你比 TypeScript 更清楚這裡會是哪種型別時
下面這是一段會報錯的 code
這是因為 id 若今天傳入的是 number 就無法使用字串的方法 toUpperCase() 來做轉換
function printId(id: number | string) {
  console.log(id.toUpperCase());
};
這時可以透過「型別斷言」來解決
「型別斷言」有以下兩種常見語法:
as 語法as 後如下function printId(id: number | string) {
  console.log((id as string).toUpperCase());
};
原本的 id 外加了一個 (),並指定它是 string (valuable as string)
<type> 角括號語法注意:在 React
<>會和 JSX 定義元素的寫法產生衝突,所以在 React 中應使用as關鍵字來定義型別斷言,否則會報錯唷
function printId(id: number | string) {
  console.log((<string>id).toUpperCase());
};
以下的兩段英文敘述都是擷取自官方文件
Because type assertions are removed at compile-time, there is no runtime checking associated with a type assertion
這段是在說,在 TypeScript 中型別斷言(Type Assertions)只對編譯器有影響,用來告知編譯器這裡是什麼型別。然而,一旦 TypeScript 被編譯成 JavaScript 時,型別斷言都會被「移除」,因為 JavaScript 是動態型別語言,不支持在運行時直接進行型別的檢查
來看下方這個範例吧!
把 someValue 的值斷言為 string,並調用 toUpperCase() 方法
這段 code 在 TypeScript 中是不會報錯的
let someValue: any = 123;
let upperCaseValue: string = (someValue as string).toUpperCase();
編譯成 JavaScript 後如下,型別斷言都消失了!因為數字無法調用 toUpperCase() 方法 ,所以在運行(runtime) 時就會報錯
let someValue = 123; 
let upperCaseValue = someValue.toUpperCase(); // ❌
// ❌ TypeError: someValue.toUpperCase is not a function
TypeScript only allows type assertions which convert to a more specific or less specific version of a type
這段主要在說,使用型別斷言時,只允許將型別轉換為更具體(more specific)或更廣泛(less specific version)的型別,不允許將型別斷言成一個完全無關的型別,例如:不能將「string」斷言成「number」)
這段在 TypeScript 中會報錯
const x = "hello" as number; 
// ❌ Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
as HTML....ElementHTMLDivElement:用於 <div>
HTMLInputElement:用於 <input>
HTMLAnchorElement:用於 <a>
HTMLButtonElement:用於 <button>
HTMLFormElement:用於 <form>const inputEl = document.querySelector(".test") as HTMLInputElement;
const inputEl2: HTMLInputElement = document.querySelector(".test");
Const Assertion 稱為「常數斷言」,語法是 as const ,位置通常會放在「最後面」
「常數斷言」,它用來修改型別推斷的結果,確保所有元素都被指派為 Literal Types,而不是其他型別,例如:string, number
用在變數宣告或表達式的型別上時,它會強制將變數或表達式的型別視為常數,是不可變的(immutable),只可讀取 (readonly)
const directions = ['up', 'down', 'left', 'right']      
const directions2 = ['up', 'down', 'left', 'right'] as const; // 常數斷言
第一個為一般的 Arrary; 第二個為其常數斷言,兩者推斷的結果如下
directions2 被推斷為 readonly ['up', 'down', 'left', 'right'],且值是不可變的,並且每個元素的型別都是 Literal Types
這時候對一個 directions2 進行操作(如:push()),就會報錯
directions2.push('NONE');
// ❌ Property 'push' does not exist on type 'readonly ["up", "down", "left", "right"]'.
語法:const a = expr(表達式) as any as T(特定型別);
這是一個雙重斷言的語法
第一個 as 將 某段表達式 斷言為 any
第二個 as 再斷言為特定的型別 T
附上實際範例如下
1.
interface User {
    id: number;
    name: string;
    email: string;
}
function fetchData(): any {
    return {
        id: 1,
        name: "Hannah",
        email: "hanforwork@example.com"
    };
}
const expr = fetchData();
const user = expr as any as User; // 雙重斷言, ✅ Pass
function handler(e: Event) {
  const element = (e as any) as HTMLElement; // 雙重斷言,✅ Pass
}
雖然使用「雙重斷言」可以解決某些煩人的型別問題,但應該被視為最後的選擇,過度依賴可能會掩蓋潛在的型別問題,降低可維護性和安全性。只有在確定無法透過其他更安全的方法解決型別問題時,才考慮使用這種方法
每天講的內容有推到 github 上喔